/*
 *
 * (c) Copyright Ascensio System Limited 2010-2018
 *
 * The MIT License (MIT)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */


package controllers;

import com.alibaba.fastjson.JSONObject;
import helpers.DocumentManager;
import helpers.ServiceConverter;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.URL;
import java.util.Enumeration;
import java.util.Map;
import java.util.Scanner;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

import entities.FileType;
import helpers.FileUtility;

import org.primeframework.jwt.domain.JWT;

@MultipartConfig
@WebServlet(name = "IndexServlet", urlPatterns = {"/IndexServlet"})
public class IndexServlet extends HttpServlet {

    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String action = request.getParameter("type");

        if (action == null) {
            request.getRequestDispatcher("index.jsp").forward(request, response);
            return;
        }

        DocumentManager.init(request, response);
        PrintWriter writer = response.getWriter();

        switch (action.toLowerCase()) {
            case "upload":
                upload(request, response, writer);
                break;
            case "convert":
                convert(request, response, writer);
                break;
            case "track":
                track(request, response, writer);
                break;
            default:
                System.out.println("没有配置的类型：" + action.toLowerCase());
        }
    }


    private static void upload(HttpServletRequest request, HttpServletResponse response, PrintWriter writer) {

        System.out.println("Upload===============================================");
        response.setContentType("text/plain");

        try {
            Part httpPostedFile = request.getPart("file");

            String fileName = "";
            for (String content : httpPostedFile.getHeader("content-disposition").split(";")) {
                if (content.trim().startsWith("filename")) {
                    fileName = content.substring(content.indexOf('=') + 1).trim().replace("\"", "");
                }
            }

            long curSize = httpPostedFile.getSize();
            if (DocumentManager.getMaxFileSize() < curSize || curSize <= 0) {
                writer.write("{ \"error\": \"File size is incorrect\"}");
                return;
            }

            String curExt = FileUtility.getFileExtension(fileName);
            if (!DocumentManager.getFileExts().contains(curExt)) {
                writer.write("{ \"error\": \"File type is not supported\"}");
                return;
            }

            InputStream fileStream = httpPostedFile.getInputStream();

            fileName = DocumentManager.getCorrectName(fileName);
            String fileStoragePath = DocumentManager.storagePath(fileName, null);

            File file = new File(fileStoragePath);

            try (FileOutputStream out = new FileOutputStream(file)) {
                int read;
                final byte[] bytes = new byte[1024];
                while ((read = fileStream.read(bytes)) != -1) {
                    out.write(bytes, 0, read);
                }

                out.flush();
            }

            writer.write("{ \"filename\": \"" + fileName + "\"}");

        } catch (IOException | ServletException e) {
            writer.write("{ \"error\": \"" + e.getMessage() + "\"}");
            e.printStackTrace();
        }
    }

    private static void convert(HttpServletRequest request, HttpServletResponse response, PrintWriter writer) {
        System.out.println("Convert===============================================");
        response.setContentType("text/plain");

        try {
            String fileName = request.getParameter("filename");
            String fileUri = DocumentManager.getFileUri(fileName);
            String fileExt = FileUtility.getFileExtension(fileName);
            FileType fileType = FileUtility.getFileType(fileName);
            String internalFileExt = DocumentManager.getInternalExtension(fileType);

            if (DocumentManager.getConvertExts().contains(fileExt)) {
                String key = ServiceConverter.generateRevisionId(fileUri);

                String newFileUri = ServiceConverter.getConvertedUri(fileUri, fileExt, internalFileExt, key, true);

                if (newFileUri.isEmpty()) {
                    writer.write("{ \"step\" : \"0\", \"filename\" : \"" + fileName + "\"}");
                    return;
                }

                String correctName = DocumentManager.getCorrectName(FileUtility.getFileNameWithoutExtension(fileName) + internalFileExt);

                URL url = new URL(newFileUri);
                java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
                InputStream stream = connection.getInputStream();

                if (stream == null) {
                    throw new Exception("Stream is null");
                }

                File convertedFile = new File(DocumentManager.storagePath(correctName, null));
                try (FileOutputStream out = new FileOutputStream(convertedFile)) {
                    int read;
                    final byte[] bytes = new byte[1024];
                    while ((read = stream.read(bytes)) != -1) {
                        out.write(bytes, 0, read);
                    }

                    out.flush();
                }

                connection.disconnect();

                //remove source file ?
                //File sourceFile = new File(DocumentManager.StoragePath(fileName, null));
                //sourceFile.delete();

                fileName = correctName;
            }

            writer.write("{ \"filename\" : \"" + fileName + "\"}");

        } catch (Exception ex) {
            writer.write("{ \"error\": \"" + ex.getMessage() + "\"}");
            ex.printStackTrace();
        }
    }

    private static void track(HttpServletRequest request, HttpServletResponse response, PrintWriter writer) {
        System.out.println("Track===============================================");

        Map<String, String[]> parameterMap = request.getParameterMap();

        for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
            String[] value = entry.getValue();
            if (value != null && value.length > 0) {
                System.out.println(entry.getKey() + "==>" + value[0]);
            }
        }

        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()) {
            System.out.println("======>>" + parameterNames.nextElement());
        }

        String userAddress = request.getParameter("userAddress");
        String fileName = request.getParameter("fileName");

        String storagePath = DocumentManager.storagePath(fileName, userAddress);
        String body = "";

        try {
            Scanner scanner = new Scanner(request.getInputStream());
            scanner.useDelimiter("\\A");
            body = scanner.hasNext() ? scanner.next() : "";
            scanner.close();
        } catch (Exception ex) {
            writer.write("get request.getInputStream error:" + ex.getMessage());
            ex.printStackTrace();
            return;
        }

        if (body.isEmpty()) {
            writer.write("empty request.getInputStream");
            return;
        }

        JSONObject jsonObj = JSONObject.parseObject(body);

        int status;
        String downloadUri;

        if (DocumentManager.tokenEnabled()) {
            String token = (String) jsonObj.get("token");

            JWT jwt = DocumentManager.readToken(token);
            if (jwt == null) {
                writer.write("JWT.parse error");
                return;
            }

            status = jwt.getInteger("status");
            downloadUri = jwt.getString("url");
        } else {
            status = Long.valueOf(String.valueOf(jsonObj.get("status"))).intValue();
            downloadUri = (String) jsonObj.get("url");
        }

        System.out.println("JSON:" + jsonObj.toJSONString());
        System.out.println("downloadUri:" + downloadUri);
        System.out.println("storagePath:" + storagePath);

        int saved = 0;
        //MustSave, Corrupted
        if (status == 2 || status == 3) {
            try {
                URL url = new URL(downloadUri);
                java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
                InputStream stream = connection.getInputStream();

                if (stream == null) {
                    throw new Exception("Stream is null");
                }

                File savedFile = new File(storagePath);
                try (FileOutputStream out = new FileOutputStream(savedFile)) {
                    System.out.println("开始下载更新文件");
                    int read;
                    final byte[] bytes = new byte[1024];
                    while ((read = stream.read(bytes)) != -1) {
                        out.write(bytes, 0, read);
                    }

                    out.flush();
                }

                connection.disconnect();

            } catch (Exception ex) {
                saved = 1;
                ex.printStackTrace();
            }
        }

        writer.write("{\"error\":" + saved + "}");
    }


    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        processRequest(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        processRequest(request, response);
    }

    @Override
    public String getServletInfo() {
        return "Handler";
    }
}
